package wfb.definitions;

import java.util.Arrays;
import java.util.Iterator;
import java.util.TreeMap;


/** Klasse zur Kapselung von Statistik-Daten fuer mehrere Laender und
 * pro Land fuer mehrere Jahre.
 * Im Konstruktor werden die Attributnamen zu den statistischen Daten
 * in der Reihenfolge angegeben, wie sie spaeter uebergeben werden.
 * Mittels addData() werden jeweils fuer ein Land und ein Jahr alle
 * statistischen Daten wie im Konstruktor angegeben uebergeben.
 */
public class StatData implements StatDataInterface {

  /** Liste der Laender (Top-Level-Struktur) */
  private TreeMap<String,TreeMap<String,String[]>> countries = new TreeMap<String,TreeMap<String,String[]>>();
  
  /** Enthaelt Namen der Statistik-Attribute in der Reihenfolge,
   * in der sie bei addData uebergeben werden (ohne Land und Jahr) */
  private String[] attrNames = null;
  
  /** Konstruktor 
   * @param attrNames  Namen der Statistik-Attribute in der Reihenfolge,
   *                   in der sie bei addData uebergeben werden (ohne Land
   *                   und Jahr)
   */
  public StatData(String[] attrNames) {
    this.attrNames = attrNames;
  }
  
  /**
	 * Wandelt Array in einen String (Kommaseparierte Liste).
	 * @param arr Array
	 * @return String
	 */
  private String arrayToString(Object arr[]) {
    StringBuffer strBuf = new StringBuffer();
		for (Object anArr : arr) strBuf.append(anArr.toString()).append(", ");
		if (strBuf.length() > 0) strBuf.setLength(strBuf.length() -2);
    return strBuf.toString();
  }
  
  /** Fuegt einen neuen Datensatz hinzu.
   * @param country  Name des Landes auf das sich die stat. Daten beziehen
   * @param year  Jahr auf das sich die statistischen Daten beziehen
   * @param statData  die statistischen Daten fuer das angegebene Land
   *                  und Jahr in der Anzahl und Reihenfolge, wie sie als
   *                  Attributnamen im Konstruktor uebergeben wurden
   * @exception WfbDbException  wenn die Anzahl der Daten in statData nicht
   *                            mit der Anzahl der Attributnamen, die im 
   *                            Konstruktor uebergeben wurden, uebereinstimmt
   *                            oder ein Datensatz fuer dieses Land und dieses
   *                            Jahr schon existiert
   */
  public void addData(String country, String year, String[] statData)
    throws WfbDbException {
    
    TreeMap<String,String[]> years;  // Liste der Jahre fuer ein Land
    
    if (statData.length != attrNames.length)
      throw new WfbDbException("Anzahl der stat. Daten stimmt nicht mit " +
                               "Anzahl der Attributnamen ueberein!" +
                               "\nLand: " + country + "  Jahr: " + year +
                               "\nAttributnamen: " + arrayToString(attrNames) +
                               "\nDaten: " + arrayToString(statData));
    
    if ((years = countries.get(country)) == null)
      // Land noch nicht bekannt -> einfuegen
      countries.put(country, years = new TreeMap<String,String[]>());

    if (years.containsKey(year))
      throw new WfbDbException("Statistische Daten fuer dieses Land und Jahr " +
                               "schon vorhanden! Land: " + country +
                               "  Jahr: " + year);
    
    years.put(year, statData);
  }

  /** Liefert die Attributnamen der statistischen Daten in der Reihenfolge,
   * in der die Daten vorliegen.
   * @return Attributnamen der statistischen Daten in der Reihenfolge,
   *         in der die Daten vorliegen; die Iterator-Objekte sind Strings
   */
  public Iterator<String> getAttrNames() {
    return Arrays.asList(attrNames).iterator();
  }
  
  /** Liefert einen Iterator ueber alle Laender zu denen statistische Daten
   * vorliegen.
   * @return Iterator ueber Namen der Laender; die iterierten Objekte sind
   *         vom Typ String; die Namen der Laender sind alphabetisch
   *         sortiert
   */
  public Iterator<String> getCountries() {
    return countries.keySet().iterator();
  }
  
  /** Liefert Iterator ueber alle Jahr zu denen statistische Daten fuer das
   * angegebene Land vorliegen
   * @param country  Name des Landes fuer das die Jahre zurueckgegeben werden
   * @return Iterator ueber alle Jahre fuer die Daten fuer dieses Land
   *         vorliegen oder <code>null</code>, wenn das Land nicht bekannt ist;
   *         die Jahre sind aufsteigend sortiert
   */
  public Iterator<String> getYears(String country) {
    TreeMap<String,String[]> years;
    if ((years = countries.get(country)) == null) {
      return null;
    }
    return years.keySet().iterator();
  }
  
  /** Liefert einen Iterator ueber die statistischen Daten eines Landes fuer
   * ein bestimmtes Jahr.
   * @param country  Land fuer das die Daten geliefert werden sollen
   * @param year  Jahr fuer das die Daten geliefert werden sollen
   * @return Iterator ueber alle statistischen Daten fuer das angegebene Land
   *         und Jahr oder <code>null</code>, wenn das Land nicht bekannt ist
   *         oder kein Eintrag fuer das Jahr zu diesem Land existiert;
   *         die Daten werden in der Reihenfolge geliefert, wie beim Aufruf
   *         von getAttrNames(); die Iterator-Objekte sind vom Typ String
   */
  public Iterator<String> getData(String country, String year) {
    TreeMap<String,String[]> years;
    String[] data;
    
    if ((years = countries.get(country)) == null)
      return null;
    
    if ((data = years.get(year)) == null)
      return null;
    
    return Arrays.asList(data).iterator();
  }
}
